package org.upo.eps.it.phama.struts.action;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.hibernate.HibernateException;
import org.upo.eps.it.phama.bean.Proveedor;
import org.upo.eps.it.phama.bean.DetallePedPro;
import org.upo.eps.it.phama.bean.DetallePedProId;
import org.upo.eps.it.phama.bean.Estado;
import org.upo.eps.it.phama.bean.PedidoProveedor;
import org.upo.eps.it.phama.bean.Producto;
import org.upo.eps.it.phama.dao.ProveedorDAO;
import org.upo.eps.it.phama.dao.EstadoDAO;
import org.upo.eps.it.phama.dao.PedidoProveedorDAO;
import org.upo.eps.it.phama.struts.actionform.PedidosProveedorActionForm;

/**
 *
 * @author grupo 4
 */
public class PedidosProveedorAction extends Action {

    /**
     * This is the action called from the Struts framework.
     *
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        HttpSession session = request.getSession();
        String result = "login";
        /* Los métodos execute de todos los Action efectúan la misma comprobación. Si la sesión
         * guarda un atributo User es porque hay un usuario identificado, por lo que se puede
         * continuar con la ejecución del método. Si no lo hay, se redirige al usuario a la página
         * de logado.
         */
        if (session.getAttribute("user") != null) {
            /* Si hay un usuario logado, se efectúa la acción determinada por el atributo
             * opción del ActionForm asociado.
             */
            PedidosProveedorActionForm af = (PedidosProveedorActionForm) form;
            String opcion = af.getOpcion().toLowerCase();
            switch (opcion) {
                case "menu":
                    result = "menu";
                    break;
                case "cancelar":
                    result = cancelar(request);
                    break;
                case "grabar":
                    result = crear(af, response.getWriter());
                    break;
                case "buscar":
                    result = buscar(af, response.getWriter());
                    break;
                case "eliminar":
                    result = eliminar(af, response.getWriter());
                    break;
                case "modificar":
                    result = modificar(af, response.getWriter());
                    break;
                case "buscardetalle":
                    result = buscarDetalle(af, response.getWriter(), request);
                    break;
                case "anadirdetalle":
                    result = anadirDetalle(af, response.getWriter(), request);
                    break;
                case "eliminardetalle":
                    result = eliminarDetalle(af, response.getWriter(), request);
                    break;
            }
        }
        return mapping.findForward(result);
    }

//<editor-fold defaultstate="collapsed" desc="private methods">
    private String cancelar(HttpServletRequest request) {
        /* Cuando se pulsa el botón cancelar, se debe eliminar el atributo de sesión que
         * guarda la lista de los artículos asociados al pedido.
         */
        HttpSession session = request.getSession();
        session.removeAttribute("detallePedido");
        return "success";
    }

    private String buscar(PedidosProveedorActionForm form, PrintWriter out) {
        /* Se obtiene el resultado de la búsqueda de pedidos que permanece guardado en una colección
         * del ActionForm asociado. Después se recorre y se genera una cadena JSON que será la que se 
         * devuelva en el objeto response y que será debidamente tratada por el proveedor.
         */
        String result = "failure";
        form.setResultadoBusqueda(PedidoProveedorDAO.search(form.getIdProveedor(), form.getId(), form.getFecha()));
        JSONArray jsonArray = new JSONArray();
        try {
            for (PedidoProveedor pedido : form.getResultadoBusqueda()) {
                JSONObject json = new JSONObject();
                json.put("id", pedido.getIdPedidoPro());
                json.put("fecha", pedido.getFecha());
                json.put("nota", pedido.getNotas());
                json.put("idEstado", pedido.getEstado() != null ? pedido.getEstado().getIdEstado() : "");
                json.put("descripcionEstado", pedido.getEstado() != null ? pedido.getEstado().getDescripcion() : "");
                json.put("idProveedor", pedido.getProveedor() != null ? pedido.getProveedor().getIdProveedor() : "");
                json.put("nombreProveedor", pedido.getProveedor() != null ? pedido.getProveedor().getNombre() : "");
                json.put("contactoProveedor", pedido.getProveedor() != null ? pedido.getProveedor().getContacto() : "");
                json.put("correoProveedor", pedido.getProveedor() != null ? pedido.getProveedor().getEmail() : "");
                json.put("telefonoproveedor", pedido.getProveedor() != null ? pedido.getProveedor().getTelefono() : "");
                jsonArray.put(json);
            }
            out.print(jsonArray);
            result = "success";
        } catch (JSONException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } catch (Exception ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } finally {
            return result;
        }
    }

    
    private String crear(PedidosProveedorActionForm form, PrintWriter out) {
        /* La petición de creación de un pedido pasa por hacerlo persistente en la base de datos. Para
         * ello es necesario obtener una referencia a los objetos Estado y Proveedor, que son atributos
         * del pedido.
         * Si se produce alguna excepción, se genera una cadena que se añade al objeto response para
         * el tratamiento por parte del proveedor.
         */
        String result = "failure";
        try {
            Estado estado = EstadoDAO.getById(form.getEstado());
            Proveedor proveedor = ProveedorDAO.getById(form.getIdProveedor());
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            Date fecha = (Date) formatter.parse(form.getFecha());
            PedidoProveedor pedido = new PedidoProveedor(estado, proveedor, fecha, form.getNotas());
            pedido.getMisDetallesPedPro().addAll(form.getDetallePedido());

            PedidoProveedorDAO.save(pedido);

            result = "success";
        } catch (HibernateException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } catch (Exception ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } finally {
            return result;
        }
    }

    
    private String eliminar(PedidosProveedorActionForm form, PrintWriter out) {
        /* Cuando se solicita eliminar un pedido, se ejecuta el método correspondiente de la 
         * clase DAO. Cualquier excepción es devuelta como cadena mediante la respuesta HTTP.
         */
        String result = "failure";
        try {
            PedidoProveedorDAO.delete(form.getId());
            result = "success";
        } catch (HibernateException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getCause()));
            out.println("</div>");
        } finally {
            return result;
        }
    }

    private String modificar(PedidosProveedorActionForm form, PrintWriter out) {
        /* Modificar un pedido es similar a su creación, solo que en esta ocasión es necesario
         * asignar al objeto a persistir el número de pedido, que había sido obtenido 
         * durante la búsqueda.
         */
        String result = "failure";
        try {
            Estado estado = EstadoDAO.getById(form.getEstado());
            Proveedor proveedor = ProveedorDAO.getById(form.getIdProveedor());
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            Date fecha = (Date) formatter.parse(form.getFecha());
            PedidoProveedor pedido = new PedidoProveedor(estado, proveedor, fecha, form.getNotas());
            // Se obtiene el número de pedido que está guardado en un atributo del ActionForm.
            pedido.setIdPedidoPro(form.getId());
            pedido.getMisDetallesPedPro().addAll(form.getDetallePedido());

            PedidoProveedorDAO.update(pedido);

            result = "success";
        } catch (HibernateException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } catch (Exception ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } finally {
            return result;
        }
    }

    private String buscarDetalle(PedidosProveedorActionForm form, PrintWriter out, HttpServletRequest request) {
        /* Cada vez que se solicita modificar un pedido se efectua la búsqueda de todos los artículos que lo
         * componen. Esta búsqueda permite construir una cadena JSON que será devuelta en el objeto response
         * para ser posteriormente tratada por el proveedor.
         */
        String result = "failure";
        HttpSession session = request.getSession();
        List<DetallePedPro> detalles = PedidoProveedorDAO.searchDetalle(form.getId());
        form.setDetallePedido(detalles);
        session.setAttribute("detallePedido", detalles);
        JSONArray jsonArray = new JSONArray();
        try {
            int orden = 0;
            for (DetallePedPro det : detalles) {
                DetallePedProId id = new DetallePedProId();
                id.setIdDetalle(orden);
                det.setId(id);
                JSONObject json = new JSONObject();
                json.put("codigo", det.getProducto().getIdProducto());
                json.put("descripcionProducto", det.getProducto().getNombre());
                json.put("cantidad", det.getCantidad());
                json.put("precio", det.getProducto().getPrecio());
                json.put("iva", det.getProducto().getIva());
                json.put("idDetalle", det.getId().getIdDetalle());
                jsonArray.put(json);
                orden++;
            }
            out.println(jsonArray);
            result = "success";
        } catch (JSONException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } catch (Exception ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        } finally {
            return result;
        }
    }

    private String anadirDetalle(PedidosProveedorActionForm form, PrintWriter out, HttpServletRequest request) {
        /* Cada vez que se añade un artículo al detalle se obtiene del ActionForm la colección que contiene
         * la lista y se le añade el artículo en cuestión.
         * La lista completa es pasada de vuelta al proveedor como cadena JSON. No se grabará hasta que el usuario
         * lo solicite.
         */
        String result = "failure";
        HttpSession session = request.getSession();
        List<DetallePedPro> detalles = form.getDetallePedido();
        DetallePedPro detalle = new DetallePedPro();
        Producto articulo = form.getProductoSeleccionado();

        detalle.setProducto(articulo);
        detalle.setCantidad(form.getCantidad());
        detalles.add(detalle);

        session.setAttribute("detallePedido", detalles);

        JSONArray jsonArray = new JSONArray();
        try {
            int orden = 0;
            for (DetallePedPro det : detalles) {
                /* Se recorre la lista de artículos y se genera la cadena JSON. A cada 
                 * artículo se le asigna un idDetalle que será su posición en la lista y que
                 * servirá para futuras peticiones de eliminación. El idDetalle será parte
                 * de la clave primaria compuesta del objeto detalle (DetallePedPro).
                 */
                DetallePedProId id = new DetallePedProId();
                id.setIdDetalle(orden);
                det.setId(id);
                JSONObject json = new JSONObject();
                json.put("codigo", det.getProducto().getIdProducto());
                json.put("descripcionProducto", det.getProducto().getNombre());
                json.put("cantidad", det.getCantidad());
                json.put("precio", det.getProducto().getPrecio());
                json.put("iva", det.getProducto().getIva());
                json.put("idDetalle", det.getId().getIdDetalle());
                jsonArray.put(json);
                orden++;
            }
            out.println(jsonArray);
            result = "success";
        } catch (JSONException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        }

        return result;
    }

    private String eliminarDetalle(PedidosProveedorActionForm form, PrintWriter out, HttpServletRequest request) {
        /* Para eliminar un artículo de la lista de detalle, primero se recupera la misma del ActionForm y después
         * se itera hasta encontrar un artículo con el mismo idDetalle. En ese caso, el artículo se elimina de 
         * la lista y toda ella se vuelve a iterar para construir la cadena JSON que será devuelta en el 
         * objeto response para que el proveedor la trate.
         */
        String result = "failure";
        HttpSession session = request.getSession();
        List<DetallePedPro> detalles = (List<DetallePedPro>) session.getAttribute("detallePedido");
        boolean enc = false;
        try {
            Iterator it = detalles.iterator();
            while (!enc && it.hasNext()) {
                DetallePedPro det = (DetallePedPro) it.next();
                if (det.getId().getIdDetalle() == form.getIdDetalle()) {
                    detalles.remove(det);
                    enc = true;
                }
            }
            session.setAttribute("detallePedido", detalles);
            JSONArray jsonArray = new JSONArray();

            int orden = 0;
            for (DetallePedPro det : form.getDetallePedido()) {
                DetallePedProId id = new DetallePedProId();
                id.setIdDetalle(orden);
                det.setId(id);
                JSONObject json = new JSONObject();
                json.put("codigo", det.getProducto().getIdProducto());
                json.put("descripcionProducto", det.getProducto().getNombre());
                json.put("precio", det.getProducto().getPrecio());
                json.put("iva", det.getProducto().getIva());
                json.put("cantidad", det.getCantidad());
                json.put("idDetalle", det.getId().getIdDetalle());
                jsonArray.put(json);
                orden++;
            }
            out.println(jsonArray);
            result = "success";
        } catch (JSONException ex) {
            out.println("<div id='excepcion'>");
            out.println(String.format("<ul><li>Se ha producido el siguiente error: %s</li></ul>", ex.getMessage()));
            out.println("</div>");
        }

        return result;
    }
    //</editor-fold>
}
